<?php

namespace app\service;

use Exception;
use OSS\OssClient;
use OSS\Core\OssException;
use AlibabaCloud\Client\AlibabaCloud;
use AlibabaCloud\Client\Exception\ClientException;
use AlibabaCloud\Client\Exception\ServerException;

class OssService
{
    public static ?OssService $_instance       = null;
    protected string          $accessKeyId     = 'owenweb';
    protected string          $accessKeySecret = 'owenweb';
    protected string          $endpoint        = 'http://oss-cn-shanghai.aliyuncs.com';
    protected string          $regionId        = 'cn-shanghai';
    protected string          $bucket          = 'owenweb';

    /**
     * @return OssService|mixed
     */
    public static function instance(): ?OssService
    {
        if (!static::$_instance) static::$_instance = new self();
        return static::$_instance;
    }

    /**
     * @param string $filePath
     * @param string $fileName
     * @return false|null
     */
    public function uploadFile(string $filePath, string $fileName = '')
    {
        $date            = date('Ymd');
        $accessKeyId     = $this->accessKeyId;
        $accessKeySecret = $this->accessKeySecret;
        $endpoint        = $this->endpoint;
        $object          = "source/{$date}/{$fileName}";
        try {
            $ossClient = new OssClient($accessKeyId, $accessKeySecret, $endpoint);
            return $ossClient->uploadFile($this->bucket, $object, $filePath);
        } catch (OssException $e) {
            return false;
        }
    }

    /**
     * @param string $filePath
     * @param string $fileName
     * @return false|null
     */
    public function adminUploadFile(string $filePath, string $fileName = '')
    {
        $date            = date('Ymd');
        $accessKeyId     = $this->accessKeyId;
        $accessKeySecret = $this->accessKeySecret;
        $endpoint        = $this->endpoint;
        $object          = "upload/{$date}/{$fileName}";
        $bucket          = $this->bucket;
        $ossClient       = new OssClient($accessKeyId, $accessKeySecret, $endpoint);
        return $ossClient->uploadFile($bucket, $object, $filePath);
    }

    /**
     * @param string $object
     * @return bool
     */
    public function findObject(string $object): bool
    {
        try {
            $ossClient = new OssClient($this->accessKeyId, $this->accessKeySecret, $this->endpoint);
            return $ossClient->doesObjectExist($this->bucket, $object);
        } catch (OssException $e) {
            return false;
        }
    }

    /**
     * @throws ClientException
     * @throws Exception
     */
    public function stsToken(): array
    {
        AlibabaCloud::accessKeyClient($this->accessKeyId, $this->accessKeySecret)->regionId($this->regionId)->asDefaultClient();
        //设置参数，发起请求。关于参数含义和设置方法，请参见《API参考》。
        try {
            return AlibabaCloud::rpc()->product('Sts')->scheme('https')->version('2015-04-01')->action('AssumeRole')->method('POST')->host('sts.cn-shanghai.aliyuncs.com')
                ->options([
                    'query' => [
                        'RegionId'        => $this->regionId,
                        'RoleArn'         => "acs:ram::120432258748:role/ramoss",
                        'RoleSessionName' => "ramoss",
                    ],
                ])->request()->toArray();
        } catch (ClientException|ServerException $e) {
            throw new Exception($e->getErrorMessage(), 400);
        }
    }

    /**
     * @param string $securityToken
     * @param string $object
     * @param int    $timeout
     * @return \OSS\Http\ResponseCore|string
     */
    public function getSignDownloadUrl(array $sts, string $object, int $timeout = 300)
    {
        try {
            $ossClient = new OssClient($sts['AccessKeyId'], $sts['AccessKeySecret'], $this->endpoint, false, $sts['SecurityToken']);
            // 生成GetObject的签名URL。
            $down_url = $ossClient->signUrl($this->bucket, $object, $timeout);
            $url_arr  = explode('://', $down_url);
            return 'https://' . $url_arr[1];
        } catch (OssException $e) {
            return '';
        }
    }

    /**
     * @param array $sts
     * @param array $objects
     * @return \OSS\Http\ResponseCore|string
     */
    public function deleteSignObject(array $sts, array $objects)
    {
        if (empty($objects)) return '';
        try {
            $ossClient = new OssClient($sts['AccessKeyId'], $sts['AccessKeySecret'], $this->endpoint, false, $sts['SecurityToken']);
            return $ossClient->deleteObjects($this->bucket, $objects);
        } catch (OssException $e) {
            return '';
        }
    }
}